﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using System.Threading;
using AutoMapper;
using Jarvis.Server.Providers;
using Jarvis.Server.Workers.Messages;
using Jarvis.WCF.DataContracts;
using Jarvis.WCF.ServiceContracts;
using Ninject.Extensions.Logging;

namespace Jarvis.Server.Workers
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class WCFWorker : Worker, ILocatorService,IStatisticsService
    {
        private readonly ILogger _logger;
        private readonly ILocationProvider _locationProvider;
        private readonly IStatsProvider _statsProvider;
        private readonly IMappingEngine _mapper;
        private ServiceHost _serviceHost;

        private Domain.Location _currentLocation = Domain.Location.NonRecognizedLocation;
        private Domain.Location CurrentLocation
        {
            get
            {
                lock (_currentLocation)
                {
                    return _currentLocation;
                }
            }
            set
            {
                lock (_currentLocation)
                {
                    _currentLocation = value;
                }
            }
        }
        public WCFWorker(ILogger logger, ILocationProvider locationProvider, IStatsProvider statsProvider, IMappingEngine mapper)
        {
            _logger = logger;
            _locationProvider = locationProvider;
            _statsProvider = statsProvider;
            _mapper = mapper;
            Subscribe<CurrentLocationChangedMessage>(this);

            Name = "WCF Service Worker";
        }

        public override void OnMessageReceived(Message message)
        {
            base.OnMessageReceived(message);

            var currentLocationChangedMessage = message as CurrentLocationChangedMessage;
            if (currentLocationChangedMessage != null)
            {
                CurrentLocation = currentLocationChangedMessage.Location;
            }
        }

        protected override void BeforeStart()
        {
            base.BeforeStart();
            var baseAddresses = new Uri[]
                                    {
                                        new Uri("http://localhost:9090/Jarvis"),
                                        //new Uri(Properties.Settings.Default.ServiceNamedPipeUri),
                                    };

            _serviceHost = new ServiceHost(this, baseAddresses);

            _serviceHost.AddServiceEndpoint(typeof(ILocatorService),
            new BasicHttpBinding(),
            "Location");

            //_serviceHost.AddServiceEndpoint(typeof(ILocationService),
            //  new NetNamedPipeBinding(),
            //  "Location");

            _serviceHost.AddServiceEndpoint(typeof(IStatisticsService),
            new BasicHttpBinding(),
            "Statistics");

            //_serviceHost.AddServiceEndpoint(typeof(IStatsService),
            //  new NetNamedPipeBinding(),
            //  "Stats");


            var smb = new ServiceMetadataBehavior();
            smb.HttpGetEnabled = true;
            smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
            _serviceHost.Description.Behaviors.Add(smb);

            _serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;

            _serviceHost.Open();
            
        }

        protected override void AfterStop()
        {
            base.AfterStop();
            _serviceHost.Close();
        }

        #region Overrides of Worker

        public override void Loop()
        {
            Thread.Yield();
        }

        #endregion

        #region Implementation of ILocatorService

        public IList<Location> GetKnownLocations()
        {
            return _mapper.Map<IList<Location>>(_locationProvider.KnownLocations);
        }

        public Location GetCurrentLocation()
        {
            return _mapper.Map<Location>(CurrentLocation);
        }

        public void StoreLocation(Location location)
        {
            _locationProvider.StoreAsKnownLocation(_mapper.Map<Domain.Location>(location));
        }

        public void Update(Location location)
        {
            _locationProvider.UpdateLocation(_mapper.Map<Domain.Location>(location));
        }

        public void Remove(Location location)
        {
            _locationProvider.RemoveLocation(_mapper.Map<Domain.Location>(location));
        }

        #endregion

        #region Implementation of IStatisticsService

        public IList<LocationStats> GetStatistics()
        {
            foreach (var stat in _statsProvider.GetAllStats())
            {
                _logger.Trace("Location Name for stat: {0}",stat.Location.Name);
            }
            
            _logger.Trace("Stats Entry Count");
            return _mapper.Map<IList<LocationStats>>(_statsProvider.GetAllStats());
        }

        public LocationStats GetStatisticsForLocation(Location location)
        {
            return _mapper.Map<LocationStats>(_statsProvider.StatsForLocation(_mapper.Map<Domain.Location>(location)));
        }

        #endregion
    }
}
